package com.gitee.slowcreator.http.file.download.template;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.gitee.slowcreator.http.config.ScHttpConfig;
import com.gitee.slowcreator.http.exception.HttpHandleException;
import com.gitee.slowcreator.http.file.download.DownloadResult;
import com.gitee.slowcreator.http.file.download.IFileDownload;
import com.gitee.slowcreator.http.util.FileNameUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

/**
 * @author zxw
 * @date 2023/6/10 18:28
 */
@Slf4j
public abstract class AbstractLocalFileDownload<Request, Response> implements IFileDownload<Request, Response> {

    @Override
    public DownloadResult downloadFile(Request request, Response response) {

        String dispositionHeader = getContentDisposition(request, response);
        String requestUrl = getRequestUrl(request, response);
        // 获取原始文件名
        String originFileName = FileNameUtil.getOriginFileNameFromContentDisposition(dispositionHeader, requestUrl);
        if (StrUtil.isBlank(originFileName)) {

            String extName = FileNameUtil.getExtNameFromContentType(getContentType(request, response));
            originFileName = IdUtil.fastSimpleUUID() + extName;
            log.info("下载文件文件名为空，使用默认uuid:{},文件名", originFileName);
        }

        // 构建返回的参数
        DownloadResult downloadResult = this.preBuildDownloadResult(originFileName);
        // 储存下载文件的目录 直接使用就行 父目录如果没有 调用 getSaveDestFile 会自动创建
        File destFile = this.getSaveDestFile(downloadResult);
        boolean printDownloadPercentage = ScHttpConfig.isPrintDownloadPercentage();
        try (InputStream is = getDownloadInputStream(request, response);
             OutputStream fos = Files.newOutputStream(destFile.toPath())) {

            if (is == null) {
                downloadResult.setRequestSuccess(false);
            } else {
                int size;
                long total = getFileLength(request, response);
                byte[] buf = new byte[4096];
                int len = 0;
                int percentDownloadProcess = -6;
                while ((size = is.read(buf)) != -1) {
                    len += size;
                    fos.write(buf, 0, size);
                    int process = (int) Math.floor(((double) len / total) * 100);
                    // 是否打印文件下载的百分比情况
                    if (percentDownloadProcess + 5 <= process) {
                        if (printDownloadPercentage) {
                            log.info("目标文件:{},当前下载进度:{} %", destFile.getName(), process);
                        }
                        percentDownloadProcess = process;
                    }
                }
            }
            fos.flush();
            downloadResult.setRequestSuccess(true);
        } catch (IOException e) {
            log.error("下载目标文件:{},出现异常:", destFile.getName(), e);
            downloadResult.setRequestSuccess(false);
            downloadResult.setData(e.getMessage().getBytes(StandardCharsets.UTF_8));
        }

        return downloadResult;
    }


    /**
     * 预构建返回参数
     *
     * @param originFileName 原始文件名
     * @return
     */
    private DownloadResult preBuildDownloadResult(String originFileName) {

        String downloadFileSaveBasePath = ScHttpConfig.getDownloadFileSaveBasePath();
        if (StrUtil.isBlank(downloadFileSaveBasePath)) {
            log.error("下载文件存储基础路径为空.");
            throw new HttpHandleException("下载文件存储路径不能为空!");
        }
        if (!StrUtil.endWithAny(downloadFileSaveBasePath, "/", "\\")) {
            // 添加分隔符
            downloadFileSaveBasePath = downloadFileSaveBasePath + File.separator;
        }

        return DownloadResult.builder()
                .originFileName(originFileName)
                .savePath(downloadFileSaveBasePath + DateTime.now().toString("yyyy-MM-dd"))
                .newFileName(FileNameUtil.getNewFileName(originFileName))
                .build();
    }

    /**
     * 获取文件的保存路径
     *
     * @param downloadResult 下载的一些参数
     * @return 保存目标的file
     */
    private File getSaveDestFile(DownloadResult downloadResult) {

        String newFileName = downloadResult.getNewFileName();

        String destPath = StrUtil.join("",
                downloadResult.getSavePath(),
                File.separator,
                newFileName);
        File file = new File(destPath);
        if (!file.getParentFile().exists()) {
            // 创建父目录
            FileUtil.mkParentDirs(file);
        }

        return file;
    }

    /**
     * 获取 Content-Disposition
     *
     * @param request
     * @param response
     * @return
     */
    protected abstract String getContentDisposition(Request request, Response response);

    /**
     * 获取 Content-Type
     *
     * @param request
     * @param response
     * @return
     */
    protected abstract String getContentType(Request request, Response response);

    /**
     * 获取下载输入流
     *
     * @param request
     * @param response
     * @return
     */
    protected abstract InputStream getDownloadInputStream(Request request, Response response);

    /**
     * 获取文件长度
     *
     * @param request
     * @param response
     * @return
     */
    protected abstract long getFileLength(Request request, Response response);

    /**
     * 获取请求url
     *
     * @param request
     * @param response
     * @return
     */
    protected abstract String getRequestUrl(Request request, Response response);
}
